package com.xunlai.infra.permission.business.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xunlai.infra.permission.business.converter.MemberConverter;
import com.xunlai.infra.permission.business.dao.entity.Member;
import com.xunlai.infra.permission.business.dao.entity.MembershipsGoods;
import com.xunlai.infra.permission.business.dao.entity.Order;
import com.xunlai.infra.permission.business.dao.entity.OrderGoods;
import com.xunlai.infra.permission.business.dao.entity.vo.UserMemberVo;
import com.xunlai.infra.permission.business.dao.repository.MemberRepository;
import com.xunlai.infra.permission.business.dao.repository.MembershipsGoodsRepository;
import com.xunlai.infra.permission.business.dao.repository.OrderGoodsRepository;
import com.xunlai.infra.permission.business.dao.repository.OrderRepository;
import com.xunlai.infra.permission.business.dao.repository.vo.UserMemberRepository;
import com.xunlai.infra.permission.business.service.MemberService;
import com.xunlai.infra.permission.business.service.WxPayService;
import com.xunlai.infra.permission.business.vo.member.MemberCompleteVo;
import com.xunlai.infra.permission.business.vo.member.MemberInfoVo;
import com.xunlai.infra.permission.business.vo.member.MemberQueryVo;
import com.xunlai.infra.permission.business.vo.member.RechargeVo;
import com.xunlai.infra.permission.common.exception.DataNotExistException;
import com.xunlai.infra.permission.common.exception.PermissionBusinessException;
import com.xunlai.infra.permission.common.vo.BasePageRespVo;
import com.xunlai.infra.permission.storage.entity.UserAccount;
import com.xunlai.infra.permission.storage.repository.UserAccountRepository;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Optional;
import java.util.UUID;

/**
 * @author liang
 * @date 9/8/23 7:01 PM
 */
@Service
public class MemberServiceImpl implements MemberService {

    private final Logger logger = LoggerFactory.getLogger(MemberServiceImpl.class);

    private MembershipsGoodsRepository membershipsGoodsRepository;

    private MemberRepository memberRepository;

    private OrderRepository orderRepository;

    private OrderGoodsRepository orderGoodsRepository;

    private WxPayService wxPayService;

    private UserMemberRepository userMemberRepository;

    private UserAccountRepository userAccountRepository;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public RechargeVo recharge(Long membershipsGoodsId, Long userId) throws PermissionBusinessException {
        Optional<MembershipsGoods> membershipsGoodsOptional = membershipsGoodsRepository.findById(membershipsGoodsId);
        if(membershipsGoodsOptional.isEmpty()){
            throw new DataNotExistException("充值类型不存在");
        }
        MembershipsGoods membershipsGoods = membershipsGoodsOptional.get();
        Optional<Member> memberOptional = memberRepository.findByAccountId(userId);
//        boolean newMember = memberOptional.isEmpty();
//        OrderGoods orderGoods = OrderGoods.builder().goodsId(membershipsGoodsId).orderId().build();
        Order order = new Order();
        String orderNo = UUID.randomUUID().toString().replace("-","");
        order.setOrderNo(orderNo);
        order.setOrderTime(LocalDateTime.now());
        order.setStatus(Order.OrderStatus.CREATE.getStatus());
        order.setCustomerId(userId);
        BigDecimal goodsPrice = membershipsGoods.getPrice();
        order.setTotalGoodsAmount(goodsPrice);
        BigDecimal discountAmount = discountAmount(userId, memberOptional.orElse(null));
        BigDecimal totalPayAmount = goodsPrice.subtract(discountAmount);
        order.setTotalPayAmount(totalPayAmount.intValue() < 0 ? new BigDecimal("0.01") : totalPayAmount);
        order.setTotalDiscount(discountAmount);
        Order save = orderRepository.save(order);
        OrderGoods orderGoods = new OrderGoods();
        orderGoods.setGoodsClass(MembershipsGoods.class.getSimpleName());
        orderGoods.setGoodsNum(1);
        orderGoods.setGoodsPrice(goodsPrice);
        orderGoods.setGoodsId(membershipsGoodsId);
        orderGoods.setOrderId(save.getId());
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            orderGoods.setGoodsSnapshot(objectMapper.writeValueAsString(membershipsGoods));
        } catch (JsonProcessingException e) {
            logger.error(e.getMessage(),e);
        }
        orderGoodsRepository.save(orderGoods);

        String qrCode = wxPayService.nativePay(order);
        String encode = URLEncoder.encode(qrCode, StandardCharsets.UTF_8);
        return new RechargeVo(save.getId(), "/travel/manage/photo/qrCode/generate?content=" + encode);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void completeInfo(Long accountId, MemberCompleteVo memberCompleteVo) {
        Optional<Member> memberOptional = memberRepository.findByAccountId(accountId);
        Member toSave;
        if(memberOptional.isEmpty()){
            toSave = new Member();
            toSave.setAccountId(accountId);
        }else {
            toSave = memberOptional.get();
        }
        BeanUtils.copyProperties(memberCompleteVo,toSave);
        memberRepository.save(toSave);
    }

    @Override
    public MemberInfoVo getInfo(Long accountId) {
        Optional<Member> memberOptional = memberRepository.findByAccountId(accountId);
        if(memberOptional.isEmpty()){
            return null;
        }else {
            Member member = memberOptional.get();
            return MemberConverter.INSTANCE.convertEntity2Vo(member);
        }
    }

    @Override
    public BasePageRespVo<UserMemberVo> listUserMember(Integer pageNum, Integer pageSize) {
//        mem
        pageNum = (pageNum == null || pageNum < 1) ? 1 : pageNum;
        int size = (pageSize == null || pageSize <= 0) ? 10 : pageSize;
        PageRequest pageRequest = PageRequest.of(pageNum -1 ,size);
        Page<UserMemberVo> all = userMemberRepository.findAll(pageRequest);
        return new BasePageRespVo<>(all.stream().toList(),pageNum,pageSize,all.getTotalElements(),all.getTotalPages());
    }

    @Override
    public BasePageRespVo<UserMemberVo> listUserMember(MemberQueryVo memberQueryVo, Integer pageNum, Integer pageSize) {
        UserMemberVo userAccount = new UserMemberVo();
        userAccount.setAccount(memberQueryVo.account());
        pageNum = (pageNum == null || pageNum < 1) ? 1 : pageNum;
        int size = (pageSize == null || pageSize <= 0) ? 10 : pageSize;
        PageRequest pageRequest = PageRequest.of(pageNum -1 ,size);
        Page<UserMemberVo> all = userMemberRepository.findAll(Example.of(userAccount, ExampleMatcher.matching().withIgnoreNullValues().withMatcher("account", ExampleMatcher.GenericPropertyMatcher::contains)),pageRequest);
        return new BasePageRespVo<>(all.stream().toList(),pageNum,pageSize,all.getTotalElements(),all.getTotalPages());
    }

    private BigDecimal discountAmount(Long userId, Member member){
        Optional<UserAccount> accountOptional = userAccountRepository.findById(userId);
        BigDecimal disAccount = new BigDecimal("0");
        if(accountOptional.isEmpty()){
            return disAccount;
        }
        UserAccount userAccount = accountOptional.get();
        String invitationCode = userAccount.getInvitationCode();
        if(StringUtils.isNotBlank(invitationCode)){
            disAccount = disAccount.add(new BigDecimal("30"));
        }
        if(member == null){
            return disAccount;
        }
        if(member.getContact() != null && member.getPrincipal() != null){
            //已完善信息
            disAccount = disAccount.add(new BigDecimal("20"));
        }
        return disAccount;
    }

    @Autowired
    public void setMembershipsGoodsRepository(MembershipsGoodsRepository membershipsGoodsRepository) {
        this.membershipsGoodsRepository = membershipsGoodsRepository;
    }

    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Autowired
    public void setOrderRepository(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    @Autowired
    public void setOrderGoodsRepository(OrderGoodsRepository orderGoodsRepository) {
        this.orderGoodsRepository = orderGoodsRepository;
    }

    @Autowired
    public void setWxPayService(WxPayService wxPayService) {
        this.wxPayService = wxPayService;
    }

    @Autowired
    public void setUserMemberRepository(UserMemberRepository userMemberRepository) {
        this.userMemberRepository = userMemberRepository;
    }

    @Autowired
    public void setUserAccountRepository(UserAccountRepository userAccountRepository) {
        this.userAccountRepository = userAccountRepository;
    }
}
